home *** CD-ROM | disk | FTP | other *** search
- Path: news.compuserve.com!newsmaster
- From: Philippe Verdy <100105.3120@compuserve.com>
- Newsgroups: comp.lang.c++
- Subject: Re: Help: Can't extract fractional digits of DOUBLE
- Date: 1 Apr 1996 23:35:40 GMT
- Organization: CompuServe Incorporated
- Message-ID: <4jpp8c$lhj@dub-news-svc-6.compuserve.com>
- NNTP-Posting-Host: ad15-078.compuserve.com
-
- Simon Lee (Simon Lee) s'Θcrit :
- >
- > Hello everyone,
- >
- > I'm trying to take a double value and extract each digit from the value.
- > The way I'm doing it is:
- >
- > double number = somevalue;
- >
- > 1 while(number != 0)
- > 2 {
- > 3 m_cpTerm[i] = (char)(number*10) % 10;
- > 4 number = (double)(number - (char)number) * 10.0;
- > 5
- > 6 precision++;
- > 7
- > 8 // Stop and round up if we've reached the end of double's precision.
- > 9 if (precision == DOUBLE_PREC)
- > 10 {
- > 11 if (((long)(number*10.0)%10) >= 5)
- > 12 {
- > 13 m_cpTerm[i] += 1;
- > 14 }
- > 15 break;
- > 16 }
- > 17
- > 18 i++;
- > 19 }
- >
- > Suppose number = 2.34.
- > What happens is after I get the last digit (4), it does line 4, and then
- > number = 9.99999999999, or if number was a longer value like 1.23458724,
- > after about 4 or 5 shifts to the left, random value starts appearing at
- > the end of the precision. Thus it never exits the while loop unless it
- > satisfies line 9.
- >
- > Anyone know of a solution to this problem?
- > BTW. I'm creating an arbitrary precision class, and this is used to convert
- > a double to the class.
- >
- > Please email any info or help.
- > Thank you,
- > Simon Lee
- >
- > P.S. Anyone know of a fast and simple algorithm to do
- > division?
- >
-
- Floating point numbers on most machines are not stored in a
- 10 radix, but use a binary radix, i.e. numbers are internally
- stored on the following form:
- sign * mantissa * 2 ^ exponent,
- with a constraint like: mantissa between [0.5, 1[,
- and sign in {-1; +1}, and exponent as a positive or negative
- integer.
- For example, 1.5 = +1 * 0.75 * 2 ^ + 1
- - the sign is stored as a single bit
- - the mantissa is stored as an integer with a fixed number
- of bits, which value is the rounding of the mantissa,
- scaled to a power of 2 which is the number of bits.
- - the integral signed exponent is stored as an unsigned
- integer with a fixed number of bits, after adding it a constant
- value.
- Expressed that way, this is ewuivalent to storing the number
- with the form: sign * scaled_mantissa * 2 ^ (exponent-scaling)
- where scaled_mantissa and exponent are integers only,
- and scaling is the fixed bit width of the field which is used
- to store the precision of the mantissa.
-
- Additionally, because of the constraint: mantissa in [0.5; 1[
- the unscaled_mantissa (expressed as a fixed bit-width integer)
- will always have its highest bit equal to 1. Then this bit
- does not need to be stored, and one additional bit is avai-
- lable for the precision, or this bit replaced by the sign bit.
- This property is used for storing 4-bytes floats, but not for
- 8-bytes doubles.
-
- If you don't use this bit, you can specify special values
- like denormal numbers, NaNs (Not a Number values), and
- infinity(ies), by using mantissa which do not conform to the
- constraint, or by reserving one value of the exponent for
- that usage.
-
- The IEEE commitee has defined standard definitions for
- portable float and double types, which should be used or
- recognized by most compilers (or by the way of a standard
- IEEE library): the fix the size in bits of each part, and
- the shiting value for the exponent, so that a number like
- 0.5 has a given exponent value part.
-
- ----------------------- So what ? --------------------------
-
- The problem you have is that the division by 10 you are using
- is not exact when applied on a number expressed in radix 2
- (you've got the same problem by dividing by 3 in the classic
- 10 radix). So once you have extracted a digit, the multiplica
- tion by 10, substracted from you original number does not give
- you the exact result you were expecting to.
-
- This is the same problem which occurs when you would like to
- express 1.1 in with all its digits in a radix 3. You get the
- first digits (for the integral part) you have no problems,
- because integers are exact in all radixes.
- However this is not true for fractional numbers stored in
- floating point variables.
-
- The problem is due to the limit of precision of the mantissa
- which has a fixed limited number of bits to express it.
- The more bits you have for the mantissa, the more precise
- you fractional number will be computed and stored.
-
- Within <limits.h>, you will find ANSI definitions of your
- floating point numbers implementation, so that you can
- parameterize your implementation to avoid excess of precision
- (which would really mean excess of UNprecision).
- These limits are expressed in bits or in digits (of radix 10)
- and also define an epsilon value which is the most little
- fraction which can be added to 1, for which the result is
- different from 1. Do not mismatch them !!!
-
- Don't forget also that the precision given by the mantissa
- is counting also the precision given by the integer part
- of your number:
-
- If you write 2582.56, you have 6 digits of precision in
- the 10 radix, not 2 !
-
- The same applies when using the 2 radix !!!
- 2582.56 is expressed as : +0.6305078125 * 4096, for which we
- could limit the mantissa to only 23 bits. So the most little
- bit of the mantissa would count for 1 / 2^23 =~= 1.19E-7 only,
- and the excess of precision of the previous long mantissa
- (the last "125" digits) is lost when storing the 2582.56
- number in such a float variable.
- So we will only store an approximation.
-
- If we keep the 23 bits mantissa (classic value for floats)
- we can compute this rounded mantissa by first multiplying
- the mantissa by 2^23, i.e. by multiplying it by the power of 2
- which is (23 minus the magnitude of the number).
-
-